package emulator.small;

import emulator.hardware.bits.SharedBit;

public class ViaStub {
	static final int ORB = 0;
	static final int ORA = 1;
	static final int DDRB = 2;
	static final int DDRA = 3;
	static final int T1CL = 4;
	static final int T1CH = 5;
	static final int T1LL = 6;
	static final int T1LH = 7;
	static final int T2CL = 8;
	static final int T2CH = 9;
	static final int SR = 10;
	static final int ACR = 11;
	static final int PCR = 12;
	static final int IFR = 13;
	static final int IER = 14;
	static final int ORA2 = 15;
	private SharedBit irq_out;
	private Timer timer1 = new Timer(6);
	private Timer timer2 = new Timer(5);
	int [] registers = new int [16]; 

	void setIrqOut(SharedBit irq_out)
	{
		this.irq_out = irq_out;
		this.irq_out.setValue(true);
	}
	
	private void setInterrupt(int index) {
		registers[IFR] |= (1 << index);
		checkInterrupts();
	}
	
	private void clearInterrupt(int index) {
		registers[IFR] &= ~(1 << index);
		checkInterrupts();
	}

	private void checkInterrupts() {
		if ((registers[IFR] & registers[IER] & 0x7F) != 0)
		{
			registers[IFR] |= 0x80;
			irq_out.setValue(false);
		}
		else
		{
			registers[IFR] &= 0x7F;
			irq_out.setValue(true);
		}
	}

	public void writeRegister(int reg, int data)
	{
		int byte_reg = reg & 15;
		int data_byte = data & 0xff;
		switch (byte_reg)
		{
		case T1CL:
			break;
		case T1CH:
			timer1.setTimerLatch(registers[T1CL] + (data_byte << 8));
			timer1.startTimer();
			break;
		case T1LL:
			break;
		case T1LH:
			timer1.setTimerLatch(registers[T1LL] + (data_byte << 8));
			break;
		case T2CL:
			break;
		case T2CH:
			timer2.setTimerLatch(registers[T2CL] + (data_byte << 8));
			timer2.startTimer();
			break;
		case IER:
			if ((data_byte & 0x80) != 0)
				data_byte = (data & 0x7F) | registers[IER];
			else
				data_byte = registers[IER] & ~data;
			break;
		}
		registers[byte_reg] = data_byte;
	}
	
	public int readRegister(int reg)
	{
		int byte_reg = reg & 15;
		switch(byte_reg)
		{
			case T1CL:
				clearInterrupt(6);
				break;
			case T2CL:
				clearInterrupt(5);
				break;
		}
		return registers[byte_reg];
	}
	
	public void handleClock(long tick_cnt)
	{
		timer1.handleClock(tick_cnt);
		timer2.handleClock(tick_cnt);
	}
	
	public class Timer {
		private boolean is_running;
		private long trigger_ticks;
		private long timer_latch;
		private long last_clock;
		private int irq_index;
		
		Timer(int index)
		{
			stopTimer();
			irq_index = index;
		}

		public void handleClock(long tick_cnt)
		{
			if (is_running)
			{
				if (tick_cnt >= trigger_ticks)
				{
					trigger_ticks += timer_latch;
					fire();
				}
			}
			last_clock = tick_cnt;
		}

		private void fire() {
			setInterrupt(irq_index);
		}
		
		public void startTimer()
		{
			trigger_ticks = last_clock + timer_latch;
			is_running = true;
			clearInterrupt(irq_index);
		}

		public void stopTimer() {
			is_running = false;
		}
		
		public void setTimerLatch(long latch)
		{
			timer_latch = latch;
		}
	}
}
